#pragma once
#include <iostream>
#include <fstream>
#include <string>
#include <time.h>
#include <stdarg.h>
#include <unistd.h>
#include <pthread.h>
#include "LockGuard.hpp"

static const char *fileName = "./log.txt";
bool gIsSave = false;

void SaveFile(const std::string &message)
{
    std::ofstream ofs(fileName, std::ios::app);
    if (!ofs.is_open())
        return;
    ofs << message;
    ofs.close();
}

enum
{
    DEBUG,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

std::string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
        return "\033[0m\033[1;36;44mDEBUG\033[0m";
    case INFO:
        return "\033[0m\033[1;36;44mINFO\033[0m";
    case WARNING:
        return "\033[0m\033[1;31;41mWARNING\033[0m";
    case ERROR:
        return "\033[0m\033[1;5;41;31mERROR\033[0m";
    case FATAL:
        return "\033[0m\033[1;5;31;40mFATAL\033[0m";
    default:
        return "\033[0mUnKnow\033[0m";
    }
    return std::string();
}

std::string GetTimeStr()
{
    time_t localtm = time(nullptr);
    struct tm *ts = localtime(&localtm);
    if (nullptr == ts)
        return "None";
    char buff[1024];
    snprintf(buff, sizeof buff, "%d/%d/%d %02d:%02d:%02d",
             ts->tm_year + 1900,
             ts->tm_mon + 1,
             ts->tm_mday,
             ts->tm_hour,
             ts->tm_min,
             ts->tm_sec);
    return buff;
}

pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
void LogMessage(const std::string filename, int line, const std::string funcname, bool issave, int level, const char *format, ...)
{
    std::string levelStr = LevelToString(level);
    std::string timeStr = GetTimeStr();
    pid_t selfID = getpid();

    char buff[1024];
    va_list arg;
    va_start(arg, format);
    vsnprintf(buff, sizeof buff, format, arg);
    va_end(arg);

    std::string message = "\033[0m\033[1;4;44;33m[" + timeStr + "]\033[0m" + "[" + levelStr + "]" +
                          "\033[0m\033[1;4;42;35m[" + std::to_string(selfID) + "]\033[0m" + "\033[0m\033[1;47;36m[" + filename + "]\033[0m" +
                          "\033[0m\033[1;47;36m[" + funcname + "]\033[0m" + "\033[0m\033[1;47;36m[" + std::to_string(line) + "]\033[0m" + "\033[0m\033[1;4;30;43m" + buff + "\033[0m";

    LockGuard lg(gMutex);
    if (!issave)
    {
        std::cout << message;
    }
    else
    {
        SaveFile(message);
    }
}

#define LOG(LEVEL, FORMAT, ...)                                                          \
    do                                                                                   \
    {                                                                                    \
        LogMessage(__FILE__, __LINE__, __func__, gIsSave, LEVEL, FORMAT, ##__VA_ARGS__); \
    } while (0)

#define EnableFile()    \
    do                  \
    {                   \
        gIsSave = true; \
    } while (0)

#define EnableScreen()   \
    do                   \
    {                    \
        gIsSave = false; \
    } while (0)



